package com.itheima.user.service.impl;

import behaviour.dto.FollowBehaviorDto;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.itheima.article.feign.ApArticleFeign;
import com.itheima.common.constants.BusinessConstants;
import com.itheima.common.constants.SystemConstants;
import com.itheima.common.enums.HttpCodeEnum;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.util.AppJwtUtil;
import com.itheima.common.util.RequestContextUtil;
import com.itheima.common.vo.ResultVo;
import com.itheima.user.dto.LoginDto;
import com.itheima.user.dto.UserRelationDto;
import com.itheima.user.mapper.ApUserFanMapper;
import com.itheima.user.mapper.ApUserFollowMapper;
import com.itheima.user.pojo.ApUser;
import com.itheima.user.mapper.ApUserMapper;
import com.itheima.user.pojo.ApUserFan;
import com.itheima.user.pojo.ApUserFollow;
import com.itheima.user.service.ApUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.catalina.util.RequestUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.naming.LinkException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @version 1.0
 * @description <p>APP用户信息 业务实现</p>
 * @package com.itheima.user.service.impl
 */
@Service
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {
    @Autowired
    private ApUserFollowMapper apUserFollowMapper;

    @Autowired
    private ApUserFanMapper apUserFanMapper;

    @Resource
    private ApArticleFeign apArticleFeign;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    /**
     * 登录校验
     *
     * @param loginDto
     * @return
     */
/*    @Override
    public Map<String, Object> loginCheck(LoginDto loginDto) {
        //获取用户输入的信息
        String phone = loginDto.getPhone();
        String password = loginDto.getPassword();
        HashMap<String, Object> resulMap = new HashMap<>();
        //客户没有输入信息--不登录查看
        if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(password)) {
            String token = AppJwtUtil.createToken(SystemConstants.ANONYMOUS_USER_ID);//未登录状态：0
            resulMap.put("token", token);
        } else {
            //客户输入账号密码，查询账号是否存在
            ApUser loginUser = query().eq("phone", phone).one();
            if (null == loginUser.getPhone()) {
                throw new LeadNewsException("用户不存在，请注册...");
            }
            if (null == loginUser) {
                throw new LeadNewsException("用户名或密码错误，请重新输入...");
            }
            //密码加盐
            password += loginUser.getSalt();
            String encryptedPwd = DigestUtils.md5DigestAsHex(password.getBytes());
            if (!encryptedPwd.equals(loginUser.getPassword())) {
                throw new LeadNewsException("用户名或密码错误，请重新输入...");
            }
            String token = AppJwtUtil.createToken(1L);//已登录状态：0
            resulMap.put("token", token);
            loginUser.setPassword("");
            loginUser.setSalt("");
            resulMap.put("user", JSON.toJSONString(loginUser));

        }
        return resulMap;
    }*/

    /**
     * 登录校验
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> loginCheck(LoginDto dto) {
        //1. 取出参数
        String phone = dto.getPhone();
        //2. 非空判断，是否为匿名，如果是匿名，则用户id为0
        Long loginUserId = SystemConstants.ANONYMOUS_USER_ID;
        //5. 构建map返回
        Map<String,Object> resultMap = new HashMap<String,Object>();
        String token = null;
        if(StringUtils.isNotEmpty(phone)){
            //3. 如果不是匿名，通过手机号码查询用户表
            ApUser loginUser = query().eq("phone", phone).one();
            if(null == loginUser){
                throw new LeadNewsException("手机号码或密码不存在！");
            }
            //3.1 密码校验
            // 前端密码加盐加密
            String pwd = dto.getPassword();
            pwd = DigestUtils.md5DigestAsHex((pwd+loginUser.getSalt()).getBytes());
            if(!pwd.equals(loginUser.getPassword())){
                throw new LeadNewsException("手机号码或密码不存在！");
            }
            loginUserId = Long.valueOf(loginUser.getId());

            loginUser.setPassword(null);
            loginUser.setSalt(null);
            // 用户的头像与名称
            String nickName = loginUser.getName();
            String headImage = loginUser.getImage();

            // 构建载荷数据
            Map<String, Object> claimMaps = new HashMap<>();
            claimMaps.put("id", loginUserId);
            claimMaps.put(SystemConstants.LOGIN_USER_NAME, nickName);//token里带上了昵称
            claimMaps.put(SystemConstants.LOGIN_USER_IMAGE, headImage);//token里带上了头像

            token = AppJwtUtil.createToken(claimMaps);
            resultMap.put("user", JSON.toJSONString(loginUser));
        }else{
            // 匿名
            //4. 生成token
            token = AppJwtUtil.createToken(loginUserId);
        }

        resultMap.put("token", token);
        return resultMap;
    }

    /**
     * 用户 关注与取消关注
     *
     * @param dto
     */
    @Override
    public void userFollow(UserRelationDto dto) {
        //1. 判断是否为匿名
        if (RequestContextUtil.isAnonymous()) {
            throw new LeadNewsException(HttpCodeEnum.NEED_LOGIN);
        }
        Long authorId = Long.valueOf(dto.getAuthorId());
        Long loginUserId = Long.valueOf(RequestContextUtil.getUserId());
        //2. 判断关注行为 是关注 还没取消关注
        ApUserFollow apUserFollow = getUserFollowRecord(loginUserId, authorId);
        if (dto.getOperation() == 0) {
            //3. 关注行为
            //3.1 查询user_follow表中是否存在记录，如果存在则报错 已关注了
            if (null != apUserFollow) {
                throw new LeadNewsException("已经关注过了!");
            }
            //3.2 不存在则添加记录，添加粉丝记录
            addApUserFollow(dto);
            addUserFan(loginUserId, authorId);
        } else {
            //4. 取消关系行为
            //4.1 查询user_follow表中是否存在记录
            //4.2 如果不存在，则报错 还没有关注
            if (null == apUserFollow) {
                throw new LeadNewsException("还没有关注该作者");
            }
            //4.3 存在，则删除关注记录且删除粉丝记录
            deleteUserFollow(loginUserId, authorId);
            deleteUserFan(loginUserId, authorId);
        }
        //5. 事务控制
        if (dto.getOperation() == 0) {
            //发消息给kafka
        // 构建用户行为dto
        FollowBehaviorDto behaviorDto = new FollowBehaviorDto();
        //被关注者 用户的ID
        behaviorDto.setFollowId(authorId);
        //文章
        behaviorDto.setArticleId(dto.getArticleId());
        //关注者 用户的ID
        behaviorDto.setUserId(loginUserId);
        kafkaTemplate.send(BusinessConstants.MqConstants.FOLLOW_BEHAVIOR_TOPIC, JSON.toJSONString(behaviorDto));
    }}




    /**
     * 删除粉丝记录
     *
     * @param loginUserId
     * @param authorId
     */
    private void deleteUserFan(Long loginUserId, Long authorId) {
        LambdaQueryWrapper<ApUserFan> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ApUserFan::getFansId, loginUserId);
        lqw.eq(ApUserFan::getUserId, authorId);
        apUserFanMapper.delete(lqw);
    }

    /**
     * 取消关注
     *
     * @param loginUserId
     * @param authorId
     */
    private void deleteUserFollow(Long loginUserId, Long authorId) {
        LambdaQueryWrapper<ApUserFollow> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ApUserFollow::getUserId, loginUserId);
        lqw.eq(ApUserFollow::getFollowId, authorId);
        apUserFollowMapper.delete(lqw);
    }

    /**
     * 添加粉丝记录
     *
     * @param loginUserId
     * @param authorId
     */
    private void addUserFan(Long loginUserId, Long authorId) {
        ApUserFan apUserFan = new ApUserFan();
        apUserFan.setIsShieldComment(0);// 不屏蔽
        apUserFan.setIsShieldLetter(0);// 不屏蔽
        apUserFan.setIsDisplay(1); // 允许
        apUserFan.setCreatedTime(LocalDateTime.now());
        apUserFan.setLevel(0);
        ApUser loginUser = getById(loginUserId);
        apUserFan.setFansName(loginUser.getName());
        apUserFan.setFansId(loginUserId);
        apUserFan.setUserId(authorId);
        apUserFanMapper.insert(apUserFan);
    }

    private ApUserFollow getUserFollowRecord(Long loginUserId, Long authorId) {
        LambdaQueryWrapper<ApUserFollow> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ApUserFollow::getUserId, loginUserId);
        lqw.eq(ApUserFollow::getFollowId, authorId);
        return apUserFollowMapper.selectOne(lqw);
    }

    private void addApUserFollow(UserRelationDto dto) {
        ApUserFollow apUserFollow;
        apUserFollow = new ApUserFollow();
        apUserFollow.setCreatedTime(LocalDateTime.now());
        apUserFollow.setIsNotice(1);
        apUserFollow.setLevel(0);
        apUserFollow.setFollowId(dto.getAuthorId());
        // 远程调用文章微服查询作者名称
        ResultVo<String> authorNameResult = apArticleFeign.getAuthorNameByArticleId(dto.getArticleId());
        if (!authorNameResult.isSuccess()) {
            throw new LeadNewsException("操作失败，请稍候重试!");
        }
        String authorName = authorNameResult.getData();
        apUserFollow.setFollowName(authorName);
        apUserFollow.setUserId(Integer.valueOf(RequestContextUtil.getUserId()));
        apUserFollowMapper.insert(apUserFollow);
    }
}
